import { Router } from "express";
import { CapOptions,paramsType } from "../../type";
// import { CapCallbackFn } from "../../type";
import dbconn from "@/dbconn";
import { ValidCode } from "../../type";
import { ValidCodeGenerator } from "../../utils/validCode";
import dayjs from "dayjs";
import { SendEmail } from "../../type";
import { CodeEmail } from "../../sendMail/codeEmail";
import { decrypt, encrypt } from "../../utils/crypto";
import sytanxError from "../../utils/error";
import successFlag from "../../utils/success";
import { JWT } from "../../utils/token";
import logger from "@/utils/log";

const svgCaptcha = require("svg-captcha");
//import { DbOperation } from "../../type";

/**
 * @description : 获取当前用户的ip地址
 * @param req : 将请求信息作为参数
 * @returns
 */
function ipv6ToV4(req: any) {
  let ip =
    req.headers["x-forwarded-for"] ||
    req.ip ||
    req.connection.remoteAddress ||
    req.socket.remoteAddress ||
    "";
  if (ip.split(",").length > 0) {
    ip = ip.split(",")[0];
  }
  ip = ip.substring(ip.lastIndexOf(":") + 1, ip.length);
  return ip;
}

/**
 * @description : 验证用户，是否存在用户，是否存在邮箱。
 * @param options
 * @returns
 */
async function Validate(options: CapOptions): Promise<string> {
  let { sql } = options;
  return new Promise((resolve, reject) => {
    dbconn
      .execute({ sql })
      .then((result) => {
        let { usernameCnt, emailCnt } = result.data[0];
        if (usernameCnt == "1") {
          resolve("已存在用戶名，請重新註冊");
        }
        if (emailCnt == "1") {
          resolve("已存在郵箱");
        }
        if (emailCnt == "0" && usernameCnt == "0") {
          resolve("驗證碼已發送");
        }
      })
      .catch((error) => {
        reject(error);
      });
  });
}
/**
 * @description : 注册成功后发送验证码，将验证码存入用户数据中。每隔两分钟会将验证码清除
 * @param validmessage
 * @returns
 */
async function CodeSave(validmessage: ValidCode): Promise<boolean> {
  const { validCode, userName, timeRecord } = validmessage;
  let datetime: string = dayjs().format("YYYY-MM-DD HH:mm:ss");
  let sql = `insert into UserValidCode values('${userName}','${validCode}','${timeRecord}',convert(varchar(24),'${datetime}',120))`;
  return new Promise((resolve, reject) => {
    dbconn
      .execute({ sql })
      .then((res) => {
        if (res.code === 200) {
          resolve(true);
        }
      })
      .catch((error) => {
        reject(error);
      });
  });
}

/**
 * @description :用户登录成功后修改登录状态、最后登录时间以及最后登录ip地址
 * @param ip
 * @param userid
 * @returns
 */
async function ChangeIP(ip: string, userid: string): Promise<boolean> {
  let sql = `update LoginStatus set ip_address = '${ip.trim()}',login_status = 'Y',last_login=getdate() where userid='${userid.trim()}'`;
  return new Promise((resolve, reject) => {
    dbconn
      .execute({ sql })
      .then((res) => {
        if (res.code === 200) {
          resolve(true);
        }
      })
      .catch(() => {
        reject(false);
      });
  });
}

export default (router: Router) => {
  //获取登录图片验证码接口
  router.post("/captcha", (req, res) => {
    const {width,height} = req.body
    const captcha = svgCaptcha.create({
      inverse: false, // 翻转颜色
      fontSize: 48, // 字体大小
      noise: 4, // 干扰线条数
      width: width || 150, // 宽度
      height: height || 50, // 高度
      size: 6, // 验证码长度
      ignoreChars: "0o1i", // 验证码字符中排除 0o1i
      color: true, // 验证码是否有彩色
      background: "#cc9966", // 验证码图片背景颜色
    });
    //保存到cookie,忽略大小写
    res.cookie("captcha", captcha.text.toLowerCase(),{sameSite:"none",secure:true,httpOnly:false});
    res.send({code:200,data:[captcha.data,captcha.text.toLowerCase()],message:'获取成功'});

  });

  //登錄
  router.post("/login", async (req, res) => {
    let { username, password ,forcelogin } = req.body;
    password = decrypt(password); //先做AES解密還原成密碼明文
    password = encrypt(password); //明文密碼再做MD5加密
    const ipAddress = ipv6ToV4(req);
    let sql = `select  a.userid,b.login_status,b.ip_address from UserInfo a left join LoginStatus b on a.userid = b.userid`;
    sql += ` where a.username = @username and a.password = @password`;
    const paraUser:Array<paramsType> = [{name:'username',value:username},{name:'password',value:password}]
    try {
      const result = await dbconn.execute({ sql,params: paraUser});
      let token = JWT.createtoken(
        { username: username, password: password },
        60*60*24
      );
      //当用户登录状态为Y时，如果上次登录ip地址相同则允许登录。如果不同返回已有登录状态，看是否需要强行登录
      //当状态为N时，可以直接登陆，并记录ip，强行登录forcelogin为Y
      if (
        result.data.length > 0 &&
        ((result.data[0].login_status === "Y" &&
          result.data[0].ip_address === ipAddress) ||
          result.data[0].login_status !== "Y" || forcelogin === "Y")
      ) {
        logger.info(`用戶：${username} 登錄成功 IP地址: ${ipAddress}`);
        try {
          await ChangeIP(ipAddress, result.data[0].userid as string);
          res.send({
            code: 200,
            message: "登錄成功",
            data: { token: token },
          });
        } catch {
          res.send(JSON.stringify({ ...sytanxError }));
        }
      }
      //用户已登录并且用户上次登录的ip地址与当前登录的ip地址不一致
      else if (
        result.data.length > 0 &&
        result.data[0].login_status === "Y" &&
        result.data[0].ip_address !== ipAddress &&
        forcelogin === "N"
      ) {
        res.send({
          code: 202,
          message: "用戶已登錄",
          data: [],
        });
      } else {
        res.send({
          code: 201,
          message: "用戶名或密碼錯誤",
          data: [],
        });
      }
    } catch (err) {
      res.send(JSON.stringify({ ...sytanxError,message:err }));
    }
  });

  //發送驗證碼--不采用Promise链式结构，采用await形式
  router.post("/sendcode", (req, res) => {
    //先判斷用戶名--郵箱是否註冊過
    let { username, email } = req.body;
    let sql =
      "select (select count(*) from UserInfo where username = '" +
      username.trim() +
      "') as usernameCnt";
    sql +=
      " ,(select count(*) from UserInfo where email = '" +
      email.trim() +
      "') as emailCnt";

    Validate({ sql })
      .then((result) => {
        if (result == "驗證碼已發送") {
          //需要生成6位數驗證碼和時間戳，存儲在數據庫中
          const validCode: ValidCode = ValidCodeGenerator.apply(username);
          CodeSave(validCode)
            .then((result) => {
              if (result) {
                //發送郵箱驗證碼--需要等待發送出去再返回數據
                let emailM: SendEmail = {
                  from: "2472904756@qq.com",
                  to: email,
                  subject: "註冊驗證碼",
                  html: `<p>你的驗證碼是：${validCode.validCode}。兩分鐘內有效</p>`,
                };
                CodeEmail(emailM)
                  .then((result) => {
                    if (result) {
                      res.send(
                        JSON.stringify({
                          code: 200,
                          message: result,
                          data: [{ message: "驗證碼已發送" }],
                        })
                      );
                    }
                  })
                  .catch((err) => {
                    res.send(
                      JSON.stringify({
                        code: 200,
                        message: "郵件發送異常,正常接收驗證碼",
                        data: err,
                      })
                    );
                  });
              } else {
                res.send(
                  JSON.stringify({
                    code: 0,
                    message: "系統異常",
                    data: [],
                  })
                );
              }
            })
            .catch((error) => {
              res.send(
                JSON.stringify({
                  code: 0,
                  message: "系統異常",
                  data: error,
                })
              );
            });
        } else {
          res.send(
            JSON.stringify({
              code: 0,
              message: result,
            })
          );
        }
      })
      .catch((error) => {
        res.send(
          JSON.stringify({
            code: 0,
            message: "系統異常",
            data: error,
          })
        );
      });
  });

  //註冊
  router.post("/regist", (req, res) => {
    let { username, password, useremail, validcode } = req.body;
    password = decrypt(password); //先AES解密
    validcode = decrypt(validcode);
    //註冊數據已經通過驗證--只需驗證一下驗證碼是否通過

    let sql = `select * from UserValidCode where validcode = '${validcode}' and username = '${username}'`;
    dbconn
      .execute({ sql })
      .then((result) => {
        if (result) {
          let uuid = new Date().getTime().toString().trim();
          let datetime: string = dayjs().format("YYYY-MM-DD HH:mm:ss");
          password = encrypt(password); //MD5加密
          sql = `insert into UserInfo values ('${uuid}','${username}','${password}','${useremail}','',convert(varchar(24),'${datetime}',120),null)`;
          dbconn
            .execute({ sql })
            .then((result) => {
              if (result) {
                res.send(JSON.stringify({ ...successFlag }));
              }
            })
            .catch(() => {
              res.send(JSON.stringify({ ...sytanxError }));
            });
        } else {
          res.send({
            code: 0,
            message: "驗證碼不正確或已失效",
            data: [],
          });
        }
      })
      .catch(() => {
        res.send(JSON.stringify({ ...sytanxError }));
      });
  });
  return router;
};
